package com.lky.remote.listener;

import com.lky.remote.annotation.EnableRemoteConfig;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class PropertiesListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {

    Logger logger = LoggerFactory.getLogger(getClass());

    //获取配置文件存放节点名称
    private String nodeName;

    //配置转化对象
    private Properties properties = new Properties();

    //系统配置对象
    private ConfigurableEnvironment environment;

    private ApplicationEnvironmentPreparedEvent preparedEvent;

    public CuratorFramework getClient(){

        //获取zookeeper的链接地址
        String connectInfo = this.environment.getProperty("config.zookeeper.url");

        //获取程序应用名来当做zookeeper的namespace
        String namespace = this.environment.getProperty("spring.application.name");

        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);

        //构建对象
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString(connectInfo)
                .sessionTimeoutMs(5000)
                .connectionTimeoutMs(5000)
                .retryPolicy(retryPolicy)
                .namespace(namespace)
                .build();

        if (client != null) client.start();

        return client;
    }

    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {

        this.preparedEvent = event;

        //判断是否启用了远程配置
        if (!isEnableRemote()){

            logger.info("没有启动远程文件配置，初始化失败");

            return;
        }

        this.environment = event.getEnvironment();

        //获取配置文件存放节点
        this.nodeName = environment.getProperty("config.zookeeper.nodename");

        logger.info("配置文件节点为"+this.nodeName);

        //获取zookeeper的里面储存信息
        try {
            this.init();
        } catch (Exception e) {
            e.printStackTrace();
        }

        PropertiesPropertySource propertySource = new PropertiesPropertySource("remote",properties);

        //将properties资源文件加载到spring中
        event.getEnvironment().getPropertySources().addFirst(propertySource);
    }

    private void init() throws Exception {

        /**
         * 1. 获取zookeeper中所有的配置
         *
         * 2. 将所有的配置存到Map对象中
         */

        //创建一个map来储存数据
        Map<String,String> map = new HashMap<>();

        CuratorFramework client = getClient();

        List<String> keys = client.getChildren().forPath("/" + nodeName);

        for (String key : keys) {

            //根据key查询出value值来
            byte[] bytes = client.getData().forPath("/" + nodeName + "/" + key);

            String values = new String(bytes,"utf-8");

            map.put(key,values);
        }

        logger.info("配置文件的所有信息为"+map);

        properties.putAll(map);
    }

    /**
     *
     * @return 是否启用了远程配置文件
     */
    public boolean isEnableRemote(){

        Object application = null;

        Set<Object> allSources = this.preparedEvent.getSpringApplication().getAllSources();

        Iterator<Object> iterator = allSources.iterator();

        while (iterator.hasNext()){
            application = iterator.next();
            break;
        }

        //获取启动类名，判断是否开启了EnableRemoteConfig注解
        String className = application.toString().replace("class","").trim();

        boolean isEnableRemote = false;

        try {
            isEnableRemote = Class.forName(className).isAnnotationPresent(EnableRemoteConfig.class);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();

            return false;
        }

        return isEnableRemote;

    }

}